package pa14.asmt.a2;

import java.util.List;
import java.util.Map;

import soot.*;
import soot.jimple.InvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.internal.JVirtualInvokeExpr;
import soot.options.Options;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.util.Chain;

public class asmt2 {

	public static void main(String[] args) {
		PackManager.v().getPack("wjtp").add(new Transform("wjtp.analyzeClassTranform", new SceneTransformer() {
			
			@SuppressWarnings("rawtypes")
			@Override
			protected void internalTransform(String arg0, Map arg1) {
				//G.v().out.println(body.getMethod());
				
				Chain<SootClass> m = soot.Scene.v().getApplicationClasses();
				
				SootClass c = soot.Scene.v().getMainClass();
				G.v().out.println("The main class is :" + c.getName());
				
				for(SootClass appClass: m){
					/*if(appClass.isConcrete()){
						G.v().out.println("This class is concrete!");
					}*/
					G.v().out.println("No of fields in " + appClass.getName() + ": " + appClass.getFieldCount());
			
					G.v().out.println("Fields for " + appClass.getName());
					
					for(SootField sootfield: appClass.getFields()){
						G.v().out.println("\tFound field: " + sootfield.getName().toString());
					}
					G.v().out.println();
					G.v().out.println("Methods for :" + appClass.getName());
					
					
					for(SootMethod method: appClass.getMethods()){
						G.v().out.println();
						G.v().out.println("\tFound method: " + method.getName().toString());
						G.v().out.println("\tSignature: " + method.getSignature().toString());
						G.v().out.println("\tParameters: ");
						if(method.getParameterCount() != 0){
							for(int param=0; param<method.getParameterCount();param++){
								G.v().out.println("\t\tParameter " + param  + ": " + method.getActiveBody().getParameterLocal(param));
							}
						}else{
							G.v().out.println("\t\tNo Parameters!");
						}
						if(method.hasActiveBody()){
							//G.v().out.println("This method has an active body!");
							//Exceptions
							List<SootClass> excepts = method.getExceptions();
							G.v().out.println("\tExceptions: ");
							for(SootClass t: excepts){
								G.v().out.println("\t\tThrows exception: " + t.toString());
							}
							//Local vars
							G.v().out.println("\tGetting Local Variables: ");
							for(Local localvar: method.getActiveBody().getLocals()){
								G.v().out.println("\t\tFound local var: " + localvar.toString() + "\ttype: " + localvar.getType().toString());
							}
							//Method calls
							G.v().out.println("\tTrying to get method calls!");
							PatchingChain<Unit> units = method.getActiveBody().getUnits();
							for(Unit u: units){
								Stmt s = (Stmt)u;
								
								
								if(s.containsInvokeExpr()){
									//G.v().out.println(s.toString() + " has invoke expression");
									InvokeExpr e = s.getInvokeExpr();
									if(e instanceof JVirtualInvokeExpr){
										G.v().out.println("\t\tMETHOD CALL HERE: " + s.toString());
										//G.v().out.println("\t\tThis method call is from class: \n\t\t\t" + s.getClass().toString() + " and our appClass is: \n\t\t\t" + appClass.toString());
									}
								}else{
									//G.v().out.println(s.toString() + " has NO invoke expression");
								}
							}
							
						}
						
					}
				}
			}
		}));
		
		Options.v().set_whole_program(true);
		soot.Main.main(args);
		
	}
	
	public static class ClassFileAnalysis{
		public ClassFileAnalysis(ExceptionalUnitGraph g){

		}
	}

}
